{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "<img src=\"../imgs/tensorflow_head.png\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Tensorflow\n",
    "\n",
    ">**TensorFlow** (https://www.tensorflow.org/) is a software library, developed by Google Brain Team within Google's Machine Learning Intelligence research organization, for the purposes of conducting machine learning and deep neural network research. \n",
    "\n",
    ">TensorFlow combines the computational algebra of compilation optimization techniques, making easy the calculation of many mathematical expressions that would be difficult to calculate, instead.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Tensorflow Main Features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Defining, optimizing, and efficiently calculating mathematical expressions involving multi-dimensional arrays (tensors).\n",
    "\n",
    "* Programming support of **deep neural networks** and machine learning techniques.\n",
    "\n",
    "* Transparent use of GPU computing, automating management and optimization of the same memory and the data used. You can write the same code and run it either on CPUs or GPUs. More specifically, TensorFlow will figure out which parts of the computation should be moved to the GPU.\n",
    "\n",
    "* High scalability of computation across machines and huge data sets.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    ">TensorFlow is available with Python and C++ support, but the **Python API** is better supported and much easier to learn."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Very Preliminary Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "11\n"
     ]
    }
   ],
   "source": [
    "# A simple calculation in Python\n",
    "x = 1\n",
    "y = x + 10\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<tf.Variable 'y:0' shape=() dtype=int32_ref>\n"
     ]
    }
   ],
   "source": [
    "# The ~same simple calculation in Tensorflow\n",
    "x = tf.constant(1, name='x')\n",
    "y = tf.Variable(x+10, name='y')\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "**Meaning**: \"When the variable `y` is computed, take the value of the constant `x` and add `10` to it\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Sessions and Models\n",
    "\n",
    "To actually calculate the value of the `y` variable and to evaluate expressions, we need to **initialise** the variables, and then create a **session** where the actual computation happens"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "model = tf.global_variables_initializer()  # model is used by convention"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "11\n"
     ]
    }
   ],
   "source": [
    "with tf.Session() as session:\n",
    "    session.run(model)\n",
    "    print(session.run(y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Data Flow Graph"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "* (**IDEA**) \n",
    "_A Machine Learning application is the result of the repeated computation of complex mathematical expressions, thus \n",
    "we could describe this computation by using a **Data Flow Graph**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "* **Data Flow Graph**: a graph where:\n",
    "    - each Node represents the _instance_ of a mathematical operation \n",
    "        - `multiply`, `add`, `divide`\n",
    "    - each Edge is a multi-dimensional data set (`tensors`) on which the operations are performed."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Tensorflow Graph Model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* **Node**: In TensorFlow, each node represents the instantion of an operation. \n",
    "    - Each operation has inputs (`>= 2`) and outputs `>= 0`.\n",
    "    \n",
    "* **Edges**: In TensorFlow, there are two types of edge:\n",
    "    - Data Edges: \n",
    "    They are carriers of data structures (`tensors`), where an output of one operation (from one node) becomes the input for another operation.\n",
    "    - Dependency Edges: These edges indicate a _control dependency_ between two nodes (i.e. \"happens before\" relationship). \n",
    "        + Let's suppose we have two nodes `A` and `B` and a dependency edge connecting `A` to `B`. This means that `B` will start its operation only when the operation in `A` ends. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Tensorflow Graph Model (cont.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* **Operation**: This represents an abstract computation, such as adding or multiplying matrices. \n",
    "    - An operation manages tensors, and It can just be polymorphic: the same operation can manipulate different tensor element types. \n",
    "        + For example, the addition of two int32 tensors, the addition of two float tensors, and so on.\n",
    "\n",
    "* **Kernel**: This represents the concrete implementation of that operation. \n",
    "    - A kernel defines the implementation of the operation on a particular device. \n",
    "        + For example, an `add matrix` operation can have a CPU implementation and a GPU one."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Tensorflow Graph Model Session"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Session**: When the client program has to establish communication with the TensorFlow runtime system, a session must be created. \n",
    "    \n",
    "As soon as the session is created for a client, an initial graph is created and is empty. It has two fundamental methods:\n",
    "\n",
    "* `session.extend`: To be used during a computation, requesting to add more operations (nodes) and edges (data). The execution graph is then extended accordingly.\n",
    "\n",
    "* `session.run`: The execution graphs are executed to get the outputs (sometimes, subgraphs are executed thousands/millions of times using run invocations)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Tensorboard"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TensorBoard** is a visualization tool, devoted to analyzing Data Flow Graph and also to better understand the machine learning models. \n",
    "\n",
    "It can view different types of statistics about the parameters and details of any part of a computer graph graphically. It often happens that a graph of computation can be very complex."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Tensorboard Example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Run the **TensorBoard** Server:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    "tensorboard --logdir=/tmp/tf_logs\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "[Open TensorBoard](http://localhost:6006)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "95\n"
     ]
    }
   ],
   "source": [
    "a = tf.constant(5, name=\"a\")\n",
    "b = tf.constant(45, name=\"b\")\n",
    "y = tf.Variable(a+b*2, name='y')\n",
    "model = tf.global_variables_initializer()\n",
    "\n",
    "with tf.Session() as session:\n",
    "    # Merge all the summaries collected in the default graph.\n",
    "    merged = tf.summary.merge_all() \n",
    "    \n",
    "    # Then we create `SummaryWriter`. \n",
    "    # It will write all the summaries (in this case the execution graph) \n",
    "    # obtained from the code's execution into the specified path”\n",
    "    writer = tf.summary.FileWriter(\"tmp/tf_logs_simple\", session.graph)\n",
    "    session.run(model)\n",
    "    print(session.run(y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Data Types (Tensors)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## One Dimensional Tensor (Vector)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "tensor_1d = np.array([1, 2.5, 4.6, 5.75, 9.7])\n",
    "tf_tensor=tf.convert_to_tensor(tensor_1d,dtype=tf.float64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1.    2.5   4.6   5.75  9.7 ]\n",
      "1.0\n",
      "4.6\n"
     ]
    }
   ],
   "source": [
    "with tf.Session() as sess: \n",
    "    print(sess.run(tf_tensor))\n",
    "    print(sess.run(tf_tensor[0]))\n",
    "    print(sess.run(tf_tensor[2]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Two Dimensional Tensor (Matrix)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0  1  2  3]\n",
      " [ 4  5  6  7]\n",
      " [ 8  9 10 11]\n",
      " [12 13 14 15]]\n",
      "[[  0.   1.   2.   3.]\n",
      " [  4.   5.   6.   7.]\n",
      " [  8.   9.  10.  11.]\n",
      " [ 12.  13.  14.  15.]]\n"
     ]
    }
   ],
   "source": [
    "tensor_2d = np.arange(16).reshape(4, 4)\n",
    "print(tensor_2d)\n",
    "tf_tensor = tf.placeholder(tf.float32, shape=(4, 4))\n",
    "with tf.Session() as sess:\n",
    "    print(sess.run(tf_tensor, feed_dict={tf_tensor: tensor_2d}))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Basic Operations (Examples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "matrix1 = np.array([(2,2,2),(2,2,2),(2,2,2)],dtype='float32') \n",
    "matrix2 = np.array([(1,1,1),(1,1,1),(1,1,1)],dtype='float32')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "tf_mat1 = tf.constant(matrix1) \n",
    "tf_mat2 = tf.constant(matrix2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "matrix_product = tf.matmul(tf_mat1, tf_mat2)\n",
    "matrix_sum = tf.add(tf_mat1, tf_mat2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "matrix_det = tf.matrix_determinant(matrix2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "with tf.Session() as sess: \n",
    "    prod_res = sess.run(matrix_product) \n",
    "    sum_res = sess.run(matrix_sum) \n",
    "    det_res = sess.run(matrix_det)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "matrix1*matrix2 : \n",
      " [[ 6.  6.  6.]\n",
      " [ 6.  6.  6.]\n",
      " [ 6.  6.  6.]]\n",
      "matrix1+matrix2 : \n",
      " [[ 3.  3.  3.]\n",
      " [ 3.  3.  3.]\n",
      " [ 3.  3.  3.]]\n",
      "det(matrix2) : \n",
      " 0.0\n"
     ]
    }
   ],
   "source": [
    "print(\"matrix1*matrix2 : \\n\", prod_res)\n",
    "print(\"matrix1+matrix2 : \\n\", sum_res)\n",
    "print(\"det(matrix2) : \\n\", det_res)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Handling Tensors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import matplotlib.image as mp_image\n",
    "filename = \"../imgs/keras-logo-small.jpg\"\n",
    "input_image = mp_image.imread(filename)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input dim = 3\n",
      "input shape = (300, 300, 3)\n"
     ]
    }
   ],
   "source": [
    "#dimension\n",
    "print('input dim = {}'.format(input_image.ndim))\n",
    "#shape\n",
    "print('input shape = {}'.format(input_image.shape))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x11829f780>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "plt.imshow(input_image)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Slicing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "my_image = tf.placeholder(\"uint8\",[None,None,3])\n",
    "slice = tf.slice(my_image,[10,0,0],[16,-1,-1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(16, 300, 3)\n"
     ]
    }
   ],
   "source": [
    "with tf.Session() as session:\n",
    "    result = session.run(slice,feed_dict={my_image: input_image})\n",
    "    print(result.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x118db7da0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(result)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Transpose"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "x = tf.Variable(input_image,name='x')\n",
    "model = tf.global_variables_initializer()\n",
    "\n",
    "with tf.Session() as session:\n",
    "    x = tf.transpose(x, perm=[1,0,2])\n",
    "    session.run(model)\n",
    "    result=session.run(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x118d33080>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(result)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Computing the Gradient\n",
    "\n",
    "- Gradients are free!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.5]\n"
     ]
    }
   ],
   "source": [
    "x = tf.placeholder(tf.float32)\n",
    "y = tf.log(x)   \n",
    "var_grad = tf.gradients(y, x)\n",
    "with tf.Session() as session:\n",
    "    var_grad_val = session.run(var_grad, feed_dict={x:2})\n",
    "    print(var_grad_val)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Why Tensorflow ?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On a typical system, there are multiple computing devices. \n",
    "\n",
    "In TensorFlow, the supported device types are **CPU** and **GPU**. \n",
    "\n",
    "They are represented as strings. For example:\n",
    "\n",
    "* `\"/cpu:0\"`: The CPU of your machine.\n",
    "* `\"/gpu:0\"`: The GPU of your machine, if you have one.\n",
    "* `\"/gpu:1\"`: The second GPU of your machine, etc."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "If a TensorFlow operation has both **CPU** and **GPU** implementations, the GPU devices will be given priority when the operation is assigned to a device. \n",
    "\n",
    "For example, `matmul` has both CPU and GPU kernels. On a system with devices `cpu:0` and `gpu:0`, `gpu:0` will be selected to run `matmul`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Example 1. Logging Device Placement\n",
    "\n",
    "`tf.Session(config=tf.ConfigProto(log_device_placement=True))`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "# Creates a graph.\n",
    "a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')\n",
    "b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')\n",
    "c = tf.matmul(a, b)\n",
    "# Creates a session with log_device_placement set to True.\n",
    "sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))\n",
    "# Runs the op.\n",
    "print(sess.run(c))\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "```\n",
    "Device mapping:\n",
    "/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GeForce GTX 760, pci bus\n",
    "id: 0000:05:00.0\n",
    "b: /job:localhost/replica:0/task:0/gpu:0\n",
    "a: /job:localhost/replica:0/task:0/gpu:0\n",
    "MatMul: /job:localhost/replica:0/task:0/gpu:0\n",
    "[[ 22.  28.]\n",
    " [ 49.  64.]]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Using Multiple GPUs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "# Creates a graph.\n",
    "c = []\n",
    "for d in ['/gpu:0', '/gpu:1']:\n",
    "  with tf.device(d):\n",
    "    a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3])\n",
    "    b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2])\n",
    "    c.append(tf.matmul(a, b))\n",
    "with tf.device('/cpu:0'):\n",
    "  sum = tf.add_n(c)\n",
    "# Creates a session with log_device_placement set to True.\n",
    "sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))\n",
    "# Runs the op.\n",
    "print sess.run(sum)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "```\n",
    "Device mapping:\n",
    "/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GeForce GTX 760, pci bus\n",
    "id: 0000:02:00.0\n",
    "/job:localhost/replica:0/task:0/gpu:1 -> device: 1, name: GeForce GTX 760, pci bus\n",
    "id: 0000:03:00.0\n",
    "Const_3: /job:localhost/replica:0/task:0/gpu:0\n",
    "Const_2: /job:localhost/replica:0/task:0/gpu:0\n",
    "MatMul_1: /job:localhost/replica:0/task:0/gpu:0\n",
    "Const_1: /job:localhost/replica:0/task:0/gpu:1\n",
    "Const: /job:localhost/replica:0/task:0/gpu:1\n",
    "MatMul: /job:localhost/replica:0/task:0/gpu:1\n",
    "AddN: /job:localhost/replica:0/task:0/cpu:0\n",
    "[[  44.   56.]\n",
    " [  98.  128.]]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## More on Tensorflow\n",
    "\n",
    "[Official Documentation](https://www.tensorflow.org/versions/r0.10/get_started/)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
